package com.cavy.platform.server.repository.impl;

import com.cavy.platform.server.ResultList;
import com.cavy.platform.server.domain.Plugin;
import com.cavy.platform.server.domain.PluginRepositorySetting;
import com.cavy.platform.server.dto.PluginSearchDto;
import com.cavy.platform.server.repository.PluginRepository;
import com.cavy.platform.server.util.FileUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.internal.storage.file.FileRepository;
import org.eclipse.jgit.lib.Repository;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.Arrays;
import java.util.Comparator;

import static com.cavy.platform.server.repository.impl.PluginRepositoryImpl.*;

/**
 * 插件文件存储
 */
public class RemotePluginRepositoryImpl implements PluginRepository {
    public static final String GIT_EXT = ".git";
    protected String dir;
    protected PluginRepositorySetting setting;

    public RemotePluginRepositoryImpl(String dir, PluginRepositorySetting setting) {
        this.dir = dir;
        this.setting = setting;
    }

    @Override
    public long countByName(String name, String version) {
        File file1 = getPluginDir(name, version);
        if (file1.exists()) {
            return 1;
        }
        return 0;
    }

    protected File getPluginDir(String name, String version) {
        File parent = new File(dir);
        if (!parent.exists()) {
            parent.mkdirs();
        }
        File file = new File(dir, name);
        return new File(file, version);
    }

    @Override
    public void create(Plugin plugin) throws IOException {
        throw new UnsupportedOperationException("不支持的操作");
    }

    @Override
    public void delete(String name, String version) {
        throw new UnsupportedOperationException("不支持的操作");
    }

    @Override
    public ResultList list(PluginSearchDto dto) {
        throw new UnsupportedOperationException("不支持的操作");
    }

    //TODO:返回{name,所属仓库名称}
    @Override
    public String[] listByDto(PluginSearchDto dto) {
        File f = new File(dir);
        String searchName = dto.getName();
        File[] files = null;
        if (!StringUtils.isEmpty(searchName)) {
            files = f.listFiles(new FilenameFilter() {
                @Override
                public boolean accept(File dir, String name) {
                    return dir.isDirectory() && !name.equals(GIT_EXT) && name.contains(searchName);
                }
            });
        } else {
            files = f.listFiles(new FileFilter() {
                @Override
                public boolean accept(File pathname) {
                    return pathname.isDirectory() && !pathname.getName().equals(GIT_EXT);
                }
            });
        }
        if (files == null || files.length == 0) return null;
        String[] result = new String[files.length];
        for (int i = 0; i < files.length; i++) {
            File file = files[i];
            result[i] = file.getName();
        }
        return result;
    }

    @Override
    public String[] getVersionList(String name) {
        File f = new File(dir, name);
        File[] files = f.listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                return pathname.isDirectory();
            }
        });
        if (files == null || files.length == 0) return null;
        Arrays.sort(files, new Comparator<File>() {
            @Override
            public int compare(File o1, File o2) {
                return o2.compareTo(o1);
//                return FileUtils.getCreateTime(o2.getPath()).compareTo(FileUtils.getCreateTime(o1.getPath()));
            }
        });
        String[] strings = new String[files.length];
        for (int i = 0; i < files.length; i++) {
            File file = files[i];
            strings[i] = file.getName();
        }

        return strings;
    }

    @Override
    public Plugin info(String name, String version) throws IOException {
        File pluginDir = getPluginDir(name, version);
        if (!pluginDir.exists()) {
            return null;
        }

        ObjectMapper mapper = new ObjectMapper();
        Plugin plugin = mapper.readValue(new File(pluginDir, OBJECT_FILE_NAME), Plugin.class);

        StringBuilder desc = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new FileReader(new File(pluginDir, DESCRIPTION_FILE_NAME)))) {
            String s = reader.readLine();
            while (!StringUtils.isEmpty(s)) {
                desc.append(s).append("\r\n");
                s = reader.readLine();
            }
        }
        plugin.setDescription(desc.toString());

        return plugin;
    }

    @Override
    public File getLogo(String name, String lastVersion) {
        File pluginDir = getPluginDir(name, lastVersion);
        return new File(pluginDir, LOGO_FILE_NAME);
    }

    @Override
    public void deleteInfo(String name, String version) {
        File pluginDir = getPluginDir(name, version);
        FileUtils.delete(new File(pluginDir, PluginRepositoryImpl.OBJECT_FILE_NAME));
    }

    @Override
    public void refresh() {
        File file = new File(dir);
        if (file.exists()) {
            pullRepository();
        } else {
            cloneRepository();
        }
    }

    @Override
    public void saveLogo(String name, String version, MultipartFile file) {
        File pluginDir = getPluginDir(name, version);
        if (file != null && !file.isEmpty()) {
            try {
                FileUtils.saveFile(file, pluginDir.getPath(), PluginRepositoryImpl.LOGO_FILE_NAME);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    private void pullRepository() {
        try (Repository repository = new FileRepository(dir + File.separator + GIT_EXT); Git git = new Git(repository)) {
            git.pull().call();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private void cloneRepository() {
        try {
            Git.cloneRepository().setURI(setting.getUrl()).setBranch(setting.getBranchName()).setDirectory(new File(dir)).call();
        } catch (GitAPIException e) {
            throw new RuntimeException(e);
        }
    }
}
